// Copyright info of this file is left out for the assignment.

#ifndef OBJMESHLOADER_H_
#define OBJMESHLOADER_H_

#include <cstdio>
#include <map>
#include <string>
#include <vector>
#include "bitmap.h"
#include "MeshLoader.h"
#include "model_obj.h"

//-----------------------------------------------------------------------------
// Alias|Wavefront OBJ file loader.
//
// This OBJ file loader contains the following restrictions:
// 1. Group information is ignored. Faces are grouped based on the material
//    that each face uses.
// 2. Object information is ignored. This loader will merge everything into a
//    single object.
// 3. The MTL file must be located in the same directory as the OBJ file. If
//    it isn't then the MTL file will fail to load and a default material is
//    used instead.
// 4. This loader triangulates all polygonal faces during importing.
//-----------------------------------------------------------------------------

namespace Loader
{
    typedef std::map<std::string, UINT> ModelTextures;

    class ObjMeshLoader : public MeshLoader
    {
    private:
        ModelOBJ* g_model;
        ID3D10Device* m_pd3dDevice;
        ModelTextures* g_modelTextures;
/*
        void UnloadModel()
        {
            SetCursor(LoadCursor(0, IDC_WAIT));

            ModelTextures::iterator i = g_modelTextures->begin();

            while (i != g_modelTextures->end())
            {
                //glDeleteTextures(1, &i->second);
                ++i;
            }

            g_modelTextures->clear();
            g_model->destroy();

            SetCursor(LoadCursor(0, IDC_ARROW));
            }
            */

        UINT LoadTexture(const char *pszFilename)
        {
            UINT id = 0;
/*            Bitmap bitmap;

            if (bitmap.loadPicture(pszFilename))
            {
                // The Bitmap class loads images and orients them top-down.
                // OpenGL expects bitmap images to be oriented bottom-up.
                bitmap.flipVertical();

                glGenTextures(1, &id);
                glBindTexture(GL_TEXTURE_2D, id);

                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

                if (g_maxAnisotrophy > 1.0f)
                {
                    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
                        g_maxAnisotrophy);
                }

                gluBuild2DMipmaps(GL_TEXTURE_2D, 4, bitmap.width, bitmap.height,
                    GL_BGRA_EXT, GL_UNSIGNED_BYTE, bitmap.getPixels());
            }
*/
            return id;
        }

    public:
        HRESULT Create( ID3D10Device* pd3dDevice, const WCHAR* strFilename )
        {
            m_pd3dDevice = pd3dDevice;
            char strName[MAX_PATH];
            wcstombs(strName, strFilename, MAX_PATH);

            // Import the OBJ file and normalize to unit length.

            SetCursor(LoadCursor(0, IDC_WAIT));

            fprintf(stdout, "Loading model \"%s\". \n", strName);

            if (!g_model->import(strName))
            {
                SetCursor(LoadCursor(0, IDC_ARROW));
                throw std::runtime_error("Failed to load model.");
                exit(0);
            }


            g_model->normalize();

            // Load any associated textures.
            // Note the path where the textures are assumed to be located.

            ModelOBJ::Material *pMaterial;
            std::string filename;

            fprintf(stdout, "Loading materials. \n");

            for (int i = 0; i < g_model->getNumberOfMaterials(); ++i)
            {
                //pMaterial = &g_model->getMaterial(i);
                //g_model->getMaterialTexture(i) = (ID3D10ShaderResourceView*)ERROR_RESOURCE_VALUE;
                
            }

            fprintf(stdout, "Model loading completed. \n");

            SetCursor(LoadCursor(0, IDC_ARROW));
        }
        UINT GetNumSubsets() const 
        {
            return g_model->getNumberOfMeshes();
        }
        UINT GetNumMaterials() const 
        {
            return g_model->getNumberOfMaterials();
        }
        void Destroy()
        {
            g_model->destroy();
        }
        D3DXVECTOR4 GetSubsetMaterialAmbient(UINT iSubset) 
        {
            return D3DXVECTOR4(g_model->getMesh(iSubset).pMaterial->ambient);
        }
        D3DXVECTOR4 GetSubsetMaterialDiffuse(UINT iSubset)
        {
            return D3DXVECTOR4(g_model->getMesh(iSubset).pMaterial->diffuse);
        }
        D3DXVECTOR4 GetSubsetMaterialSpecular(UINT iSubset)
        {
            return D3DXVECTOR4(g_model->getMesh(iSubset).pMaterial->specular);
        }
        float GetSubsetMaterialAlpha(UINT iSubset)
        {
            return g_model->getMesh(iSubset).pMaterial->alpha;
        }
        int GetSubsetMaterialSpecularPower(UINT iSubset)
        {
            return g_model->getMesh(iSubset).pMaterial->shininess;
        }
        ID3D10ShaderResourceView* GetSubsetMaterialDiffuseTxRV(UINT iSubset)
        {
            return NULL;
        }
        WCHAR* GetSubsetMaterialName(UINT iSubset)
        {
            return NULL;
        }
        ID3D10EffectTechnique* GetSubsetMaterialTech(UINT iSubset)
        {
            return NULL;
        }
        void SetMaterialTech(ID3D10Effect* g_pEffect10)
        {

        }
        void SetIAVertexIndexBuffer(ID3D10Device* pd3dDevice)
        {

        }
        void DrawSubset(ID3D10Device* pd3dDevice, UINT iSubset)
        {

        }
        float GetAutoViewDistance()
        {
            //TODO:
            return 2;
        }
    };

}

#endif //OBJMESHLOADER_H_